#include "init.h"
#include "common.h"

static struct list_head init_list_head;

void setup_init(void) 
{
	PR_INFO("setup init block list");
	INIT_LIST_HEAD(&init_list_head);
}

int try_init(struct init_block *block) 
{
	int ret = 0;

	// skip empty block
	if (block == NULL) {
		PR_INFO("skip empty init block");
		return 0;
	}

	// add block to head of block list
	list_add_tail(&block->list, &init_list_head);
	
	// if block has nothing to init, return success
	PR_INFO("begin init block %s", block->name);
	if (block->init_fn == NULL) {
		PR_INFO("block %s init is empty, init success", block->name);
		ret = 0;
	} else {
		// block has a valid init function, call it
		ret = block->init_fn(block);
		if (ret != 0) {
			// init failed, call cleanup and return
			PR_INFO("block %s, init failed, errno %d, begin cleanup", block->name, ret);
			cleanup();
		} else {
			PR_INFO("block %s, init success", block->name);
		}
	}
	return ret;
}

void cleanup(void) 
{
	struct list_head *pos, *prev;

	struct init_block *block;

	// backward iterate over init block list, call cleanup
	for (pos = init_list_head.prev, prev = pos->prev;
		pos != &init_list_head; 
		pos = prev, prev=pos->prev) {
		block = list_entry(pos, typeof(*block), list);
		PR_INFO("begin cleanup block %s", block->name);
		if (block->cleanup_fn != NULL) {
			block->cleanup_fn(block);
		}
		if (block->drop_fn != NULL) {
			PR_INFO("drop block %s", block->name);
			list_del(pos);
			block->drop_fn(block);
		}
	}
	return;
}



